package com.tjakus.hibernate;

import java.util.Date;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;

import com.tjakus.logging.Logging;

public class HibernateUtil {

	/**
	 * This is a static class which represents database initialization and queries
	 * towards database.
	 * 
	 * @author tjakus
	 * 
	 */

	private static SessionFactory sessionFactory;

	/**
	 * This constructor initialize and crates connection towards MySQL database from
	 * hibernate.cfg.xml configuration file.
	 * 
	 */
	static {
		try {
			// Create the SessionFactory from hibernate.cfg.xml
			Logging.getLogger().info(
					"HibernateUtil - initialize sessionFactory - [ ]");
			Configuration configuration = new Configuration();
			configuration.configure();
			ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()
					.applySettings(configuration.getProperties()).buildServiceRegistry();
			sessionFactory = configuration.buildSessionFactory(serviceRegistry);
		} catch (Throwable e) {
			// Make sure you log the exception, as it might be swallowed
			Logging.getLogger().error(
					"HibernateUtil - buildSessionFactory - "
							+ "[ UNABLE TO BUILD SESSION ]", e);
		}
	} 
	
	/**
	 * This method initialize and crates connection towards MySQL database from
	 * hibernate.cfg.xml configuration file.
	 * 
	 */
	public static boolean buildSessionFactory() {
		try {
			// Create the SessionFactory from hibernate.cfg.xml
			Logging.getLogger().info(
					"HibernateUtil - buildSessionFactory - [ ]");
			Configuration configuration = new Configuration();
			configuration.configure();
			ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()
					.applySettings(configuration.getProperties()).buildServiceRegistry();
			sessionFactory = configuration.buildSessionFactory(serviceRegistry);
			return true;
		} catch (Throwable e) {
			// Make sure you log the exception, as it might be swallowed
			Logging.getLogger().error(
					"HibernateUtil - buildSessionFactory - "
							+ "[ UNABLE TO BUILD SESSION ]", e);
			return false;
		}
	}

	/**
	 * This method returns Hibernate session factory.
	 * 
	 */
	public static SessionFactory getSessionFactory() {
		// Returns Hibernate session factory
		return sessionFactory;
	}

	/**
	 * This method inserts advertisement data into database. It returns true or
	 * false.
	 * 
	 */
	public static boolean addAdvetisement(Advertisement newAdvertisement) {
		Logging.getLogger().info(
				"HibernateUtil - addAdvetisement - [" + newAdvertisement.getUrl() + " "
						+ newAdvertisement.getServiceId() + " ]");
		Transaction trns = null;
		// Open session for Hibernate to connect to DB
		Session session = HibernateUtil.getSessionFactory().openSession();
		try {
			trns = session.beginTransaction();
			session.save(newAdvertisement);
			trns.commit();

		} catch (RuntimeException e) {
			Logging.getLogger().error(
					"HibernateUtil - addAdvetisement - [ UNABLE TO ADD ]", e);
			return false;
		} finally {
			// Flush and close the session
			session.flush();
			session.close();
		}
		return true;
	}

	/**
	 * This method retrieves all advertisements from database. It returns list of
	 * advertisements.
	 * 
	 */
	public List<Advertisement> getAllAdvertisements() {
		Transaction trns = null;
		Session session = HibernateUtil.getSessionFactory().openSession();
		Logging.getLogger().info(
				"HibernateUtil - getAllAdvertisements - [ ALL ADVERTISEMENTS ]");
		try {
			trns = session.beginTransaction();
			@SuppressWarnings("unchecked")
			List<Advertisement> advertisement = session.createQuery(
					"from Advertisement").list();
			for (Iterator<Advertisement> iter = advertisement.iterator(); iter
					.hasNext();) {
				Logging.getLogger().debug(
						"HibernateUtil - getAllAdvertisements - [" + iter.next().getUrl()
								+ " ]");
			}
			trns.commit();
			return advertisement;
		} catch (RuntimeException e) {
			Logging.getLogger().error(
					"HibernateUtil - getAllAdvertisements - [ UNABLE TO GET ]", e);
			return null;
		} finally {
			// Flush and close the session
			session.flush();
			session.close();
		}
	}

	/**
	 * This method retrieves advertisements from database by time stamp and
	 * service ids. It returns list of advertisements.
	 * 
	 */
	@SuppressWarnings("unchecked")
	public static List<Advertisement> getAdvertisementsByTimestampAndServiceIds(
			Timestamp timestamp, List<Integer> serviceIds) {
		Transaction trns = null;
		List<Advertisement> advertisements;
		Session session = HibernateUtil.getSessionFactory().openSession();
		Logging.getLogger().info(
				"HibernateUtil - getAdvertisementsByTimestampAndServiceIds - [ "
						+ timestamp + " " + serviceIds + " ]");
		try {
			trns = session.beginTransaction();
			advertisements = session
					.createQuery(
							"from Advertisement where timestamp >=:timestamp and service_id in :serviceIds")
					.setTimestamp("timestamp", timestamp)
					.setParameterList("serviceIds", serviceIds).list();
			trns.commit();
			for (Iterator<Advertisement> iter = advertisements.iterator(); iter
					.hasNext();) {
				Advertisement advertisement = iter.next();
				Logging.getLogger().debug(
						"HibernateUtil - getAdvertisementsByTimestampAndServiceIds - [ "
								+ advertisement.getUrl() + " ]");
			}
			return advertisements;
		} catch (RuntimeException e) {
			Logging.getLogger().error(
					"HibernateUtil - getAdvertisementsByTimestampAndServiceIds - "
							+ "[ UNABLE TO GET ]", e);
			return null;
		} finally {
			// Flush and close the session
			session.flush();
			session.close();
		}
	}

	/**
	 * This method retrieves advertisement from database by URL. It returns
	 * advertisement.
	 * 
	 */
	public static Advertisement getAdvertisementByUrl(String url) {
		Advertisement advertisement;
		Transaction trns = null;
		Logging.getLogger().info(
				"HibernateUtil - getAdvertisementByUrl - [ " + url + " ]");
		// Open session for Hibernate to connect to DB
		Session session = HibernateUtil.getSessionFactory().openSession();
		try {
			trns = session.beginTransaction();
			advertisement = (Advertisement) session
					.createQuery("from Advertisement where url like :url")
					.setString("url", url).uniqueResult();
			trns.commit();
			if (advertisement != null) {
				Logging.getLogger().info(
						"HibernateUtil - getAdvertisementByUrl - ["
								+ advertisement.getTitle() + " ]");
			}
			return advertisement;
		} catch (RuntimeException e) {
			Logging.getLogger().error(
					"HibernateUtil - getAdvertisementByUrl -[ UNABLE TO GET ] " + e);
			return null;
		} finally {
			// Flush and close the session
			session.flush();
			session.close();
		}
	}

	/**
	 * This method retrieves time stamp from database. It returns time stamp.
	 * 
	 */
	public static Timestamp getLatestTimestamp() {
		JobTimestamp jobTimestamp = null;
		Transaction trns = null;
		Logging.getLogger().info(
				"HibernateUtil - getLatestTimestamp - [ TIME STAMP ]");
		Session session = HibernateUtil.getSessionFactory().openSession();
		try {
			trns = session.beginTransaction();
			jobTimestamp = (JobTimestamp) session.createQuery("from JobTimestamp")
					.uniqueResult();
			trns.commit();
			if (jobTimestamp.getLastTimestamp() != null) {
				Logging.getLogger().debug(
						"HibernateUtil - getLatestTimestamp - ["
								+ jobTimestamp.getLastTimestamp() + " ]");
			}
			return jobTimestamp.getLastTimestamp();
		} catch (RuntimeException e) {
			Logging.getLogger().error(
					"HibernateUtil - getLatestTimestamp - [ UNABLE TO GET ]", e);
			return null;
		} finally {
			session.flush();
			session.close();
		}
	}

	/**
	 * This method deletes time stamp from database. It returns true or false.
	 * 
	 */
	public static boolean deleteLatestTimestamp() {
		Logging.getLogger().info("HibernateUtil - deleteLatestTimestamp - []");
		Transaction trns = null;
		Session session = HibernateUtil.getSessionFactory().openSession();
		try {
			trns = session.beginTransaction();
			session.createQuery("delete JobTimestamp").executeUpdate();
			trns.commit();
			return true;
		} catch (RuntimeException e) {
			Logging.getLogger().error(
					"HibernateUtil - deleteLatestTimestamp - [ UNABLE TO DELETE ]", e);
			return false;
		} finally {
			session.flush();
			session.close();
		}
	}

	/**
	 * This method updates time stamp in database. It returns true or false.
	 * 
	 */
	public static boolean updateLatestTimestamp(JobTimestamp jobTimestamp) {
		Transaction trns = null;
		Logging.getLogger().info(
				"HibernateUtil - updateLatestTimestamp - ["
						+ jobTimestamp.getLastTimestamp() + " ]");
		Session session = HibernateUtil.getSessionFactory().openSession();
		try {
			trns = session.beginTransaction();
			session.save(jobTimestamp);
			trns.commit();
			return true;
		} catch (RuntimeException e) {
			Logging.getLogger().error(
					"HibernateUtil - updateLatestTimestampById - "
							+ "[ UNABLE TO UPDATE ]", e);
			return false;
		} finally {
			session.flush();
			session.close();
		}
	}

	/**
	 * This method retrieves all users from database. It returns list of users.
	 * 
	 */
	public static List<Users> getAllUsers() {
		Transaction trns = null;
		Logging.getLogger().info("HibernateUtil - getAllUsers - [ ALL USERS ]");
		Session session = HibernateUtil.getSessionFactory().openSession();
		try {
			trns = session.beginTransaction();
			@SuppressWarnings("unchecked")
			List<Users> users = session.createQuery("from Users").list();
			for (Iterator<Users> iter = users.iterator(); iter.hasNext();) {
				Users user = new Users();
				user = iter.next();
				Logging.getLogger()
						.debug(
								"HibernateUtil - getAllUsers - [ " + user.getEmail() + ", "
										+ user.getLastTimestamp() + ", " + user.getMailCounter()
										+ " ]");
			}
			trns.commit();
			return users;
		} catch (RuntimeException e) {
			Logging.getLogger().error(
					"HibernateUtil - getAllUsers - [ UNABLE TO GET ]", e);
			return null;
		} finally {
			session.flush();
			session.close();
		}
	}

	/**
	 * This method updates user in database. It returns true or false.
	 * 
	 */
	public static boolean updateUsers(Users user) {
		Transaction trns = null;
		Logging.getLogger().info(
				"HibernateUtil - updateUsers - [" + user.getEmail() + ", "
						+ user.getLastTimestamp() + ", " + user.getMailCounter() + " ]");
		Session session = HibernateUtil.getSessionFactory().openSession();
		try {
			trns = session.beginTransaction();
			session.update(user);
			trns.commit();
			return true;
		} catch (RuntimeException e) {
			Logging.getLogger().error(
					"HibernateUtil - updateUsers - " + "[ UNABLE TO UPDATE ]", e);
			return false;
		} finally {
			session.flush();
			session.close();
		}
	}
	
	/**
	 * This method inserts user data into database. It returns true or
	 * false.
	 * 
	 */
	public static boolean addUser(String email) {
		Logging.getLogger().info(
				"HibernateUtil - addUser - [ " + email + " ]");
		Users user = new Users();
		user.setEmail(email);
		user.setMailCounter(0);
		Date date = new Date();
		// Create current time stamp
		Timestamp newTimestamp = new Timestamp(date.getTime());
		user.setLastTimestamp(newTimestamp);
		Transaction trns = null;
		// Open session for Hibernate to connect to DB
		Session session = HibernateUtil.getSessionFactory().openSession();
		try {
			trns = session.beginTransaction();
			session.save(user);
			trns.commit();

		} catch (RuntimeException e) {
			Logging.getLogger().error(
					"HibernateUtil - addUser - [ UNABLE TO ADD ]", e);
			return false;
		} finally {
			// Flush and close the session
			session.flush();
			session.close();
		}
		return true;
	}
	
	/**
	 * This method deletes user from database. It returns true or false.
	 * 
	 */
	public static boolean deleteUser(String email) {
		Transaction trns = null;
		Logging.getLogger().info(
				"HibernateUtil - deleteUser - [" + email	+ " ]");
		Session session = HibernateUtil.getSessionFactory().openSession();
		try {
			trns = session.beginTransaction();
			session.createQuery("delete Users where email like :email")
					.setString("email", email).executeUpdate();
			trns.commit();
			return true;
		} catch (RuntimeException e) {
			Logging.getLogger().error(
					"HibernateUtil - deleteUser - "
							+ "[ UNABLE TO DELETE ]", e);
			return false;
		} finally {
			session.flush();
			session.close();
		}
	}

	/**
	 * This method inserts service data into database. It returns true or
	 * false.
	 * 
	 */
	public static boolean addService(Services newService) {
		Logging.getLogger().info(
				"HibernateUtil - addService - [" + newService.getType() + " "
						+ newService.getSubType() + " ]");
		Transaction trns = null;
		// Open session for Hibernate to connect to DB
		Session session = HibernateUtil.getSessionFactory().openSession();
		try {
			trns = session.beginTransaction();
			session.save(newService);
			trns.commit();

		} catch (RuntimeException e) {
			Logging.getLogger().error(
					"HibernateUtil - addService - [ UNABLE TO ADD ]", e);
			return false;
		} finally {
			// Flush and close the session
			session.flush();
			session.close();
		}
		return true;
	}
	
	
	/**
	 * This method deletes service from database. It returns true or false.
	 * 
	 */
	public static boolean deleteService(Services service) {
		Transaction trns = null;
		Logging.getLogger().info(
				"HibernateUtil - deleteUser - [" + service.getServiceId()	+ " ]");
		Session session = HibernateUtil.getSessionFactory().openSession();
		try {
			trns = session.beginTransaction();
			session.delete(service);
			//session.createQuery("delete Users where email like :email")
			//		.setString("email", email).executeUpdate();
			trns.commit();
			return true;
		} catch (RuntimeException e) {
			Logging.getLogger().error(
					"HibernateUtil - deleteUser - "
							+ "[ UNABLE TO DELETE ]", e);
			return false;
		} finally {
			session.flush();
			session.close();
		}
	}
	

	/**
	 * This method retrieves all services from database. It returns list of
	 * services.
	 * 
	 */
	public static List<Services> getAllServices() {
		Transaction trns = null;
		Logging.getLogger().info("HibernateUtil - getAllServices - [ SERVICES ]");
		Session session = HibernateUtil.getSessionFactory().openSession();
		try {
			trns = session.beginTransaction();
			@SuppressWarnings("unchecked")
			List<Services> services = session.createQuery("from Services").list();
			for (Iterator<Services> iter = services.iterator(); iter.hasNext();) {
				Logging.getLogger().debug(
						"HibernateUtil - getAllServices - [" + iter.next().getUrl() + " ]");
			}
			trns.commit();
			return services;
		} catch (RuntimeException e) {
			Logging.getLogger().error(
					"HibernateUtil - getAllServices - [ UNABLE TO GET ]", e);
			return null;
		} finally {
			session.flush();
			session.close();
		}
	}
	
	/**
	 * This method retrieves services from database by 
	 * service ids. It returns list of services.
	 * 
	 */
	@SuppressWarnings("unchecked")
	public static List<Services> getServicesByServiceIds(List<Integer> serviceIds) {
		Transaction trns = null;
		List<Services> services;
		Session session = HibernateUtil.getSessionFactory().openSession();
		Logging.getLogger().info(
				"HibernateUtil - getServicesByServiceIds - [ " + serviceIds + " ]");
		try {
			trns = session.beginTransaction();
			services = session
					.createQuery(
							"from Services where service_id in :serviceIds")
					.setParameterList("serviceIds", serviceIds).list();
			trns.commit();
			for (Iterator<Services> iter = services.iterator(); iter
					.hasNext();) {
				Services service = iter.next();
				Logging.getLogger().debug(
						"HibernateUtil - getServicesByServiceIds - [ "
								+ service.getServiceId() + " ]");
			}
			return services;
		} catch (RuntimeException e) {
			Logging.getLogger().error(
					"HibernateUtil - getServicesByServiceIds - "
							+ "[ UNABLE TO GET ]", e);
			return null;
		} finally {
			// Flush and close the session
			session.flush();
			session.close();
		}
	}
	

	/**
	 * This method deletes all advertisements from database which are older then
	 * time stamp. It returns true or false.
	 * 
	 */
	public static boolean deleteAllOldRecordsFromAdvertisement(Timestamp timestamp) {
		Transaction trns = null;
		Logging.getLogger().info(
				"HibernateUtil - deleteAllOldRecordsFromAdvertisement - [" + timestamp
						+ " ]");
		Session session = HibernateUtil.getSessionFactory().openSession();
		try {
			trns = session.beginTransaction();
			session.createQuery("delete Advertisement where timestamp < :timestamp")
					.setTimestamp("timestamp", timestamp).executeUpdate();
			trns.commit();
			return true;
		} catch (RuntimeException e) {
			Logging.getLogger().error(
					"HibernateUtil - deleteAllOldRecordsFromAdvertisement - "
							+ "[ UNABLE TO DELETE ]", e);
			return false;
		} finally {
			session.flush();
			session.close();
		}
	}

	/**
	 * This method retrieves user mapping services ids from database. It returns
	 * list of mapping services.
	 * 
	 */
	@SuppressWarnings("unchecked")
	public static List<Integer> getMappingServiceIdsFromUser(String email) {
		List<MappingServicesToUsers> mappingServicesToUsers;
		List<Integer> serviceIds = new ArrayList<>();
		Transaction trns = null;
		Logging.getLogger().info(
				"HibernateUtil - getMappingServiceIdsFromUser - [ " + email + " ]");
		Session session = HibernateUtil.getSessionFactory().openSession();
		try {
			trns = session.beginTransaction();
			mappingServicesToUsers = session
					.createQuery("from MappingServicesToUsers where email = :email")
					.setString("email", email).list();
			trns.commit();
			for (Iterator<MappingServicesToUsers> iter = mappingServicesToUsers
					.iterator(); iter.hasNext();) {
				MappingServicesToUsers mappingServices = iter.next();
				serviceIds.add(mappingServices.getServiceId());
				Logging.getLogger().debug(
						"HibernateUtil - getMappingServiceIdsFromUser - [ "
								+ mappingServices.getServiceId() + " ]");
			}
			return serviceIds;
		} catch (RuntimeException e) {
			Logging.getLogger().error(
					"HibernateUtil - getMappingServiceIdsFromUser - "
							+ "[ UNABLE TO GET ]", e);
			return null;
		} finally {
			session.flush();
			session.close();
		}
	}

	/**
	 * This method retrieves all settings from database. It returns list of
	 * settings.
	 * 
	 */
	@SuppressWarnings("unchecked")
	public static List<Settings> getAllSettings() {
		List<Settings> settingsList = null;
		Transaction trns = null;
		Logging.getLogger().info(
				"HibernateUtil - getAllSettings - [ ]");
		// Open session for Hibernate to connect to DB
		Session session = HibernateUtil.getSessionFactory().openSession();
		try {
			trns = session.beginTransaction();
			settingsList = (List<Settings>) session
					.createQuery("from Settings").list();
			trns.commit();

			Logging.getLogger().debug(
					"HibernateUtil - getAllSettings - [  ]");
			return settingsList;
		} catch (RuntimeException e) {
			Logging.getLogger().error(
					"HibernateUtil - getAllSettings -[ UNABLE TO GET ] " + e);
			return null;
		} finally {
			// Flush and close the session
			session.flush();
			session.close();
		}
	}
	
	
	/**
	 * This method retrieves all settings from database. It returns list of
	 * settings.
	 * 
	 */
	public static String getSettingsValueByName(String settingName) {
		Settings setting = null;
		Transaction trns = null;
		Logging.getLogger().info(
				"HibernateUtil - getSettingsValueByName - [ " + settingName + " ]");
		// Open session for Hibernate to connect to DB
		Session session = HibernateUtil.getSessionFactory().openSession();
		try {
			trns = session.beginTransaction();
			setting = (Settings) session
					.createQuery("from Settings where name = :settingName")
					.setString("settingName", settingName).uniqueResult();
			trns.commit();

			Logging.getLogger().debug(
					"HibernateUtil - getSettingsValueByName - [ " + setting.getValue()
							+ " ]");
			return setting.getValue();
		} catch (RuntimeException e) {
			Logging.getLogger().error(
					"HibernateUtil - getSettingsValueByName -[ UNABLE TO GET ] " + e);
			return null;
		} finally {
			// Flush and close the session
			session.flush();
			session.close();
		}
	}
	
	/**
	 * This method updates all settings in database. 
	 * 
	 */
	public static boolean updateSettings(List<Settings> settingsList) {
		Transaction trns = null;
		Logging.getLogger().info(
				"HibernateUtil - updateSettings - [ ]");
		Session session = HibernateUtil.getSessionFactory().openSession();
		try {
			trns = session.beginTransaction();
			for (Iterator<Settings> iter = settingsList
					.iterator(); iter.hasNext();) {
				session.update(iter.next());
			}
			
			trns.commit();
			return true;
		} catch (RuntimeException e) {
			Logging.getLogger().error(
					"HibernateUtil - updateUsers - " + "[ UNABLE TO UPDATE ]", e);
			return false;
		} finally {
			session.flush();
			session.close();
		}
	}

	/**
	 * This method inserts statistic data into database. It returns true or false.
	 * 
	 */
	public static boolean addStatistic(Statistics statistic) {
		Logging.getLogger().info(
				"HibernateUtil - addStatistic - [" + statistic.getEmail() + " "
						+ statistic.getMailCounterPerDay() + " ]");
		Transaction trns = null;
		// Open session for Hibernate to connect to DB
		Session session = HibernateUtil.getSessionFactory().openSession();
		try {
			trns = session.beginTransaction();
			session.save(statistic);
			trns.commit();
		} catch (RuntimeException e) {
			Logging.getLogger().error(
					"HibernateUtil - addStatistic - [ UNABLE TO ADD ]", e);
			return false;
		} finally {
			// Flush and close the session
			session.flush();
			session.close();
		}
		return true;
	}

	/**
	 * This method retrieves list of statistics from database by email. It returns
	 * list of statistics.
	 * 
	 */
	@SuppressWarnings("unchecked")
	public static List<Statistics> getStatisticsByEmail(String email) {
		Transaction trns = null;
		List<Statistics> statisticsList = new ArrayList<>();
		Session session = HibernateUtil.getSessionFactory().openSession();
		Logging.getLogger().info(
				"HibernateUtil - getStatisticsByEmail - [ " + email + " ]");
		try {
			trns = session.beginTransaction();
			statisticsList = session
					.createQuery("from Statistics where email =:email")
					.setString("email", email).list();
			trns.commit();
			for (Iterator<Statistics> iter = statisticsList
					.iterator(); iter.hasNext();) {
				Statistics statistic = iter.next();
				Logging.getLogger().debug(
						"HibernateUtil - getStatisticsByEmail - [ "
								+ statistic.getId() + " " + statistic.getEmail() + " ]");
			}
			return statisticsList;
		} catch (RuntimeException e) {
			Logging.getLogger().error(
					"HibernateUtil - getStatisticsByEmail - "
							+ "[ UNABLE TO GET ]", e);
			return null;
		} finally {
			// Flush and close the session
			session.flush();
			session.close();
		}
	}
	
	/**
	 * This method retrieves statistic from database by email and date. It returns
	 * statistics.
	 * 
	 */
	public static Statistics getStatisticsByEmailAndDate(String email, Date date) {
		Transaction trns = null;
		Statistics statistic;
		Session session = HibernateUtil.getSessionFactory().openSession();
		Logging.getLogger().info(
				"HibernateUtil - getStatisticsByEmailAndDate - [ " + email + " " + date
						+ " ]");
		try {
			trns = session.beginTransaction();
			statistic = (Statistics) session
					.createQuery("from Statistics where email =:email and date =:date")
					.setString("email", email).setDate("date", date).uniqueResult();
			trns.commit();
			Logging.getLogger().debug(
					"HibernateUtil - getStatisticsByEmailAndDate - [ "
							+ statistic.getEmail() + " " + statistic.getMailCounter() + " ]");
			return statistic;
		} catch (RuntimeException e) {
			Logging.getLogger().error(
					"HibernateUtil - getStatisticsByEmailAndDate - "
							+ "[ UNABLE TO GET ]", e);
			return null;
		} finally {
			// Flush and close the session
			session.flush();
			session.close();
		}
	}
	
	/**
	 * This method retrieves latest statistic from database by email order by date. It returns the latest
	 * statistics.
	 * 
	 */
	public static Statistics getLatestStatisticsByEmail(String email) {
		Transaction trns = null;
		Statistics statistic;
		Session session = HibernateUtil.getSessionFactory().openSession();
		Logging.getLogger().info(
				"HibernateUtil - getLatestStatisticsByEmail - [ " + email + " ]");
		try {
			trns = session.beginTransaction();
			statistic = (Statistics) session
					.createQuery("SELECT statistic from Statistics statistic where email=:email ORDER BY statistic.date DESC")
					.setString("email", email).setMaxResults(1).uniqueResult();
			trns.commit();
			Logging.getLogger().debug(
					"HibernateUtil - getLatestStatisticsByEmail - [ "
							+ statistic.getEmail() + " " + statistic.getMailCounter() + " ]");
			return statistic;
		} catch (RuntimeException e) {
			Logging.getLogger().error(
					"HibernateUtil - getLatestStatisticsByEmail - "
							+ "[ UNABLE TO GET ]", e);
			return null;
		} finally {
			// Flush and close the session
			session.flush();
			session.close();
		}
	}
}